/**
 *    Copyright 2009 Seth Albnaese
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.aquiferserver.client.flex 
{
	import flash.events.EventDispatcher;
	import flash.net.Socket;
	import flash.events.ProgressEvent;
	import flash.utils.ByteArray;
	import mx.collections.ArrayCollection;
	import org.aquiferserver.client.flex.logging.Log;
	import org.aquiferserver.client.flex.logging.LogFactory;
	import org.aquiferserver.client.flex.GameState;
	import org.aquiferserver.client.flex.SimpleGameState;
	import org.aquiferserver.common.*;
	import flash.net.ObjectEncoding;
		
	import flash.net.registerClassAlias;
	
	/**
	 * Core Aquifer client class provides the primary API for game developers
	 * @author Seth Albanese
	 * @version $Id: AquiferClient.as 60 2009-06-15 08:47:09Z salbanese0080@gmail.com $
	 */
	
	
	public class AquiferClient extends EventDispatcher
	{
		protected static var logger:Log = LogFactory.getLog( "org.aquiferserver.client.flex.AquiferClient" );
		
		private var conn:AquiferSocket;		
		private var state:GameState;
		
		public function AquiferClient()
		{
			registerClassAlias( "org.aquiferserver.common.AquiferMessage", AquiferMessage );
			registerClassAlias( "org.aquiferserver.common.ClientMessage", ClientMessage );
			registerClassAlias( "org.aquiferserver.common.Player", Player );
			registerClassAlias( "org.aquiferserver.common.MessageType", org.aquiferserver.common.MessageType );
			registerClassAlias( "org.aquiferserver.common.HandshakeMessage", org.aquiferserver.common.HandshakeMessage );
			registerClassAlias( "org.aquiferserver.common.HandshakeConfirmationMessage", org.aquiferserver.common.HandshakeConfirmationMessage );
			registerClassAlias( "org.aquiferserver.common.PeerToPeerMessage", org.aquiferserver.common.PeerToPeerMessage );
		}
		
		[ChangeEvent( "onPeerConnect" )]
		[ChangeEvent( "onPeerDisconnect" )]
		[ChangeEvent( "clientStateChange" )]
		[ChangeEvent( "onConnect" )]
		[ChangeEvent( "onDisconnect" )]
		public function get connectedPeers() : Array { return this.gameState.peers; }		
		
		[ChangeEvent( "onConnect" )]
		[ChangeEvent( "onDisconnect" )]
		public function get clientId() : int { return this.gameState.id; }
		
		[ChangeEvent( "onConnect" )]
		[ChangeEvent( "onDisconnect" )]
		public function get connected() : Boolean { return ( conn != null ) ? conn.connected : false; }
		
		public function setPlayerData( pd:Player ) : void { this.gameState.localPlayer = pd; }
		
		public function set gameState( s:GameState ) : void { this.state = s; }
		public function get gameState() : GameState 
		{
			if ( state == null )
			{
				state = new SimpleGameState();
			}
			
			return state;
		}
		
		public function connect( server:String, port:Number ) : void
		{
			logger.info( "Connecting to " + server + " on port " + port + "..." );
			if ( conn == undefined )
			{
				conn = new AquiferSocket();
				conn.addEventListener( ProgressEvent.SOCKET_DATA, socketDataHandler );
			}
			
			conn.connect( server, port );
		}
		
		public function close() : void 
		{
			conn.close();
			
			this.gameState.id = 0;
			this.gameState.peers = new Array();
			
			dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_DISCONNECT, { connected:conn.connected } ) );
			dispatchEvent( new AquiferClientEvent( AquiferClientEvent.ON_STATE_CHANGE ) );
		}
		
		public function sendObject( value:Object ) : void 
		{			
			if ( !( value is AquiferMessage ) )
			{
				var msg:PeerToPeerMessage = new PeerToPeerMessage();
				msg.payload = value;
				sendMessage( msg );
			}
			else
			{
				sendMessage( AquiferMessage( value ) );
			}			
		}
		
		public function sendMessage( msg:AquiferMessage ) : void 
		{	
			conn.writeMessage( msg );
		}
		
		private function socketDataHandler( event:ProgressEvent ) : void
		{	
			var message:AquiferMessage = conn.readMessage();
			
			var handler:MessageHandler = MessageHandlerFactory.getMessageHandler( message.type );
			
			handler.handleMessage( message, this.gameState );
			
			if ( handler.hasResponse )
			{
				sendMessage( handler.response );
			}
			
			if ( handler.generatesEvent )
			{
				dispatchEvent( handler.event );
			}		
			
		}
	}
	
}